﻿using System.IdentityModel.Tokens.Jwt;
using System.Net;
using System.Net.WebSockets;
using System.Text;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using StudyCompanion.Commons.Authorize;
using StudyCompanion.Commons.WebSocket;

namespace StudyCompanion.Core.Middleware;

public class WebSocketManagerMiddleware
{
    private readonly JwtOption _jwtOption;
    private readonly RequestDelegate _next;

    private readonly ILogger<WebSocketManagerMiddleware> _log;

    public WebSocketManagerMiddleware(ILogger<WebSocketManagerMiddleware> log
        , RequestDelegate next
        , WebSocketHandler webSocketHandler
        , IOptions<JwtOption> jwtOption)
    {
        _log = log;
        _next = next;
        _webSocketHandler = webSocketHandler;
        _jwtOption = jwtOption.Value;
    }

    private WebSocketHandler _webSocketHandler { get; }

    public async Task Invoke(HttpContext context)
    {
        if (!context.WebSockets.IsWebSocketRequest)
            await _next.Invoke(context);

        var socket = await context.WebSockets.AcceptWebSocketAsync();
        var bearer = context.Request.Headers["Authorization"].FirstOrDefault();
        if (string.IsNullOrEmpty(bearer) || !bearer.StartsWith("Bearer"))
        {
            context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
            return;
        }


        var jwt = bearer.Split(' ');
        var tokenHandler = new JwtSecurityTokenHandler();
        var tokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuerSigningKey = true,
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtOption.Secret)), //秘钥
            ValidateIssuer = true,
            ValidIssuer = _jwtOption.Issuer,
            ValidateAudience = true,
            ValidAudience = _jwtOption.Audience,
            ValidateLifetime = true,
            ClockSkew = TimeSpan.FromMinutes(5)
        };
        var claims = tokenHandler.ValidateToken(jwt[1], tokenValidationParameters, out var validated);

        var userid = claims.FindFirst(x => x.Type == ClaimConst.UserId)?.Value;

        //TODO 用户信息处理

        _webSocketHandler.OnConnected(socket, userid);

        await Receive(socket, async (result, buffer) =>
        {
            if (result.MessageType == WebSocketMessageType.Text)
            {
                await _webSocketHandler.ReceiveAsync(socket, result, buffer);
                return;
            }

            if (result.MessageType == WebSocketMessageType.Close)
            {
                await _webSocketHandler.OnDisconnected(socket);
            }
        });
    }

    private async Task Receive(WebSocket socket, Action<WebSocketReceiveResult, byte[]> handleMessage)
    {
        try
        {
            var buffer = new byte[1024 * 4];

            while (socket.State == WebSocketState.Open)
            {
                var result = await socket.ReceiveAsync(new ArraySegment<byte>(buffer),
                    CancellationToken.None);

                handleMessage(result, buffer);
            }
        }
        catch (Exception ex)
        {
            _log.Log(LogLevel.Error, ex.Message);
        }
    }
}